package com.welsmann.framework.combiner;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.SequenceInputStream;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.Vector;

import javax.management.timer.Timer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.mozilla.javascript.ErrorReporter;
import org.mozilla.javascript.EvaluatorException;

import com.yahoo.platform.yui.compressor.CssCompressor;
import com.yahoo.platform.yui.compressor.JavaScriptCompressor;

/**
 * 静态资源处理类
 * @author Welsmann
 *
 */
public class Processor extends HttpServlet{

	private static final long serialVersionUID = -2563204360730041442L;
	
	private static String _root = "";
	
	private static final String _encoding = "UTF-8";
	
	public Processor(){
		super();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		//取得根路径
		if (!StringUtil.validateString(_root)) {
			_root = request.getSession(true).getServletContext().getRealPath("/");
		}
		
		/**
		 * 取得静态资源参数
		 * type		：	静态资源文件类型(js/css/img)
		 * expires	：	静态资源失效时间(按秒算)
		 * project	：	静态资源所属项目
		 * files	：	静态资源文件列表(仅包含文件名，无后缀)
		 */
		String type = request.getParameter("type");
		String expires = request.getParameter("expires");
		String project = request.getParameter("project");
		String files = request.getParameter("files");
		String prefix = type;
		
		//校验静态资源参数，必须全部有效才可以进行后续操作
		if (!StringUtil.validateString(type, expires, project, files)) {
			return;
		}
		
		String mime = "js".equals(type) ? "application/x-javascript" : "text/css";
		
		type = _root + type + StringUtil.getSlash();
		
		int expireTime = 0;
		
		try {
			expireTime = Integer.parseInt(expires);
			expireTime = expireTime > 0 ? expireTime : 3600;
		} catch (Exception ex) {
			expireTime = 3600;
		}
		
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.SECOND, (int)(expireTime * Timer.ONE_SECOND));
		Date expireAt = calendar.getTime();
		Locale locale = Locale.US;
		DateFormat dateFormat = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", new DateFormatSymbols(locale));
		
		response.setHeader("Cache-Control", "max-age=" + Integer.toString(expireTime, 10));
		response.setHeader("Expires", dateFormat.format(expireAt));
		response.setHeader("Content-Type", mime + "; charset=" + _encoding);
		response.setHeader("Combiner", "Static Resource Combiner, Merged by welsmann.");
		response.setHeader("Version", "1.0.6");
		
		PrintWriter writer = response.getWriter();
		
		//判断是否存在于缓存中
		MemcachedUtil _cacheUtil = new MemcachedUtil();
		String strCachedFile = _cacheUtil.get(files + "@" + project + "@" + prefix);
		
		if (StringUtil.validateString(strCachedFile)) {
			response.setHeader("Cache-Hit", "true");
			writer.write(strCachedFile);
		} else {
			Vector<String> staticFiles = new StaticFileBuilder().build(type, project, files, prefix);
			
			InputStreamReader reader = null;
			
			try {
				reader = new InputStreamReader(new SequenceInputStream(new StreamEnumerator(staticFiles)), _encoding);
			} catch (Exception ex) {
				response.setStatus(404);
				reader.close();
				return;
			} 
			
			if ("js".equalsIgnoreCase(prefix)) {
				ErrorReporter reporter = new ErrorReporter() {
					
					public void warning(String arg0, String arg1, int arg2, String arg3,
							int arg4) {
					}
					
					public EvaluatorException runtimeError(String arg0, String arg1, int arg2,
							String arg3, int arg4) {
						return new EvaluatorException(arg0);
					}
					
					public void error(String arg0, String arg1, int arg2, String arg3, int arg4) {
					}
				};
				
				try {
					JavaScriptCompressor compressor = new JavaScriptCompressor(reader, reporter);
					writer.print(_cacheUtil.put(files + "@" + project + "@" + prefix, compressor.compress(-1, true, false, false, false)));
					
				} catch (Exception ex) {
					response.setStatus(500);
					reader.close();
				}
			} else if ("css".equalsIgnoreCase(prefix)) {
				try {
					CssCompressor compressor = new CssCompressor(reader);
					writer.print(_cacheUtil.put(files + "@" + project + "@" + prefix, compressor.compress(-1)));
				} catch (Exception ex) {
					response.setStatus(500);
					reader.close();
				}
			}
			if (reader.ready()) {
				reader.close();
			}
			reader = null;
		}
		writer.close();
	}
}
